package fr.umlv.m2.uwp2011.web.client;

import java.security.MessageDigest;
import java.util.Map;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.RootPanel;

import fr.umlv.m2.uwp2011.service.user.IUserService;
import fr.umlv.m2.uwp2011.service.user.IUserServiceAsync;
import fr.umlv.m2.uwp2011.service.user.UserDTO;
import fr.umlv.m2.uwp2011.web.client.common.LoginTemplate;
import fr.umlv.m2.uwp2011.web.client.professor.ProfessorHomepage;
import fr.umlv.m2.uwp2011.web.client.professor.ProfessorMenu;
import fr.umlv.m2.uwp2011.web.client.professor.ProfessorPlanningCourse;
import fr.umlv.m2.uwp2011.web.client.professor.ProfessorPlanningWorks;
import fr.umlv.m2.uwp2011.web.client.professor.ProfessorStudents;
import fr.umlv.m2.uwp2011.web.client.professor.ProfessorTeaching;
import fr.umlv.m2.uwp2011.web.client.professor.ProfessorTeachingEditor;
import fr.umlv.m2.uwp2011.web.client.secretary.SecretaryCursusEditor;
import fr.umlv.m2.uwp2011.web.client.secretary.SecretaryHomepage;
import fr.umlv.m2.uwp2011.web.client.secretary.SecretaryMenu;

public class Application implements EntryPoint, ValueChangeHandler<String> {

	/**
	 * Professor pages index.
	 */
	public static final String PROFESSOR_PAGES = "profe";
	/**
	 * Student pages index.
	 */
	public static final String STUDENT_PAGES = "stude";
	/**
	 * Secretary pages index.
	 */
	public static final String SECRETARY_PAGES = "secre";
	/**
	 * Administrator pages index.
	 */
	public static final String ADMIN_PAGES = "admin";

	/**
	 * The login page name.
	 */
	public static final String LOGIN_PAGE = "loginPage";
	/**
	 * The professor menu name.
	 */
	public static final String PROFESSOR_MENU = "professorMenu";
	/**
	 * The professor home page name.
	 */
	public static final String PROFESSOR_HOMEPAGE = "professorHomepage";
	/**
	 * The professor teaching page name.
	 */
	public static final String PROFESSOR_TEACHING = "professorTeaching";
	/**
	 * The list of students of the professor page name.
	 */
	public static final String PROFESSOR_STUDENTS = "professorStudents";
	/**
	 * The professor planning page name.
	 */
	public static final String PROFESSOR_PLANNING_COURSE = "professorPlanningCourse";
	/**
	 * The professor planning works page name.
	 */
	public static final String PROFESSOR_PLANNING_WORKS = "professorPlanningWorks";
	/**
	 * professor editor page.
	 */
	public static final String PROFESSOR_EDITOR = "professorTeachingEditor";

	/**
	 * The secretary menu name.
	 */
	public static final String SECRETARY_MENU = "secretaryMenu";

	/**
	 * The secretary home page name.
	 */
	public static final String SECRETARY_HOMEPAGE = "secretaryHomepage";
	/**
	 * The secretary cursus editor page name
	 */
	public static final String SECRETARY_CURSUS_EDITOR = "secretaryCursusEditor";
	/**
	 * The session.
	 */
	private Session session;

	/**
	 * Creates a new {@code Application} object.
	 */
	public Application() {
		this.session = new Session();
	}

	/**
	 * Sets the session.
	 * 
	 * @param session
	 *            the session.
	 */
	public void setSession(Session session) {
		this.session = session;
	}

	/**
	 * Gets the session.
	 * 
	 * @return the session.
	 */
	public Session getSession() {
		return this.session;
	}

	@Override
	public void onModuleLoad() {
		// initialise initToken, initToken sert a savoir les pages precedent
		// visitee
		String initToken = History.getToken();
		if (initToken.length() == 0) {
			RootPanel.get("login").clear();
			History.newItem("loginPage");
		}

		// Add history listener
		History.addValueChangeHandler(this);
		// Now that we've setup our listener, fire the initial history state.
		History.fireCurrentHistoryState();
	}

	@Override
	public void onValueChange(ValueChangeEvent<String> event) {
		parseURL(event.getValue(), session.getParameters());

		if (session.getCurrentPage().equals(LOGIN_PAGE)) {
			session = new Session();
		}

		if (session.getUser().getLogin() == null) {
			this.initUser(session.getParameters());
		}
		this.initPages(session.getCurrentPage());
		this.loadPage();
	}

	/**
	 * Parse the URL in parameter and put the parameters in mapParameters.
	 * 
	 * @param url
	 *            the current URL.
	 */
	private void parseURL(String url, Map<String, String> parameters) {
		parameters.put("url", url);

		int indexOfQuestionMark = url.indexOf("?");
		if (indexOfQuestionMark < 0) {
			session.setCurrentPage(url);
		} else {
			session.setCurrentPage(url.substring(0, indexOfQuestionMark));
			url = url.substring(indexOfQuestionMark + 1);

			String[] params = url.split("&");
			for (String param : params) {
				if (!param.contains("=")) {
					break;
				}

				String name = param.split("=")[0];
				String value = param.split("=")[1];
				parameters.put(name, value);
			}
		}
	}

	private void initUser(Map<String, String> parameters) {
		if (parameters.get("login") != null && parameters.get("key") != null) {
			final String login = parameters.get("login");
			// Pour plus de securite SHA1 du
			// login+password+dateInscription+heure.
			final String key = parameters.get("key");

			IUserServiceAsync userService = GWT.create(IUserService.class);
			userService.getUser(login, new AsyncCallback<UserDTO>() {

				@Override
				public void onSuccess(UserDTO userDTO) {
					// A synchroniser avec le generateur de key.
					String checkKey = getSHA1(userDTO.getLogin());

					if (checkKey.equals(key)) {
						session.setUser(userDTO);
					} else {
						redirect("../Application.html?gwt.codesvr=127.0.0.1:9997#"
								+ LOGIN_PAGE);
					}

					initPages(session.getCurrentPage());
					loadPage();
				}

				@Override
				public void onFailure(Throwable caught) {
					redirect("../Application.html?gwt.codesvr=127.0.0.1:9997#"
							+ LOGIN_PAGE);
				}
			});
		}
	}

	private void initPages(String currentPage) {
		if (currentPage.equals(LOGIN_PAGE)) {

			this.session.addPage(currentPage, new LoginTemplate(this.session));

		} else if (currentPage.subSequence(0, 5).equals(PROFESSOR_PAGES)) {

			this.session.addPage(PROFESSOR_MENU, new ProfessorMenu(this.session));
			if (currentPage.equals(PROFESSOR_HOMEPAGE)) {

				this.session.addPage(currentPage, new ProfessorHomepage(
						this.session));

			} else if (currentPage.equals(PROFESSOR_TEACHING)) {

				this.session.addPage(currentPage, new ProfessorTeaching(this.session));

			} else if(currentPage.equals(PROFESSOR_PLANNING_COURSE)) {

				this.session.addPage(currentPage, new ProfessorPlanningCourse(this.session));

			} else if(currentPage.equals(PROFESSOR_PLANNING_WORKS)) {

				this.session.addPage(currentPage, new ProfessorPlanningWorks(this.session));

			} else if(currentPage.equals(PROFESSOR_STUDENTS)) {

				this.session.addPage(currentPage, new ProfessorStudents(
						this.session));

			} else if (currentPage.equals(PROFESSOR_EDITOR)) {

				this.session.addPage(currentPage, new ProfessorTeachingEditor(
						this.session));

			}

		} else if (currentPage.subSequence(0, 5).equals(STUDENT_PAGES)) {

			// Initialisation de la page etudiant demande.

		} else if (currentPage.subSequence(0, 5).equals(SECRETARY_PAGES)) {

			if (this.session.getPage(SECRETARY_MENU) == null) {
				this.session.addPage(SECRETARY_MENU, new SecretaryMenu(
						this.session));
			}

			if (currentPage.equals(SECRETARY_HOMEPAGE)) {

				this.session.addPage(currentPage, new SecretaryHomepage(
						this.session));

			} else if (currentPage.equals(SECRETARY_CURSUS_EDITOR)) {

				this.session.addPage(currentPage, new SecretaryCursusEditor(
						this.session));
			}

		} else if (currentPage.subSequence(0, 5).equals(ADMIN_PAGES)) {

			// Initialisation de la page admin demande.

		} else {

			this.session = new Session();
			this.session.addPage(currentPage, new LoginTemplate(this.session));

		}
	}

	/**
	 * Load the current page according parameters.
	 */
	private void loadPage() {
		String currentPage = this.session.getCurrentPage();

		RootPanel.get("login").clear();
		RootPanel.get("login").addStyleName("login");
		RootPanel.get("menu").clear();
		RootPanel.get("page").clear();

		RootPanel.get("menu").setStyleName("menu");
		RootPanel.get("page").setStyleName("page");

		Map<String, String> parameters = session.getParameters();
		parseURL(currentPage, parameters);
		session.setParameters(parameters);

		if (currentPage.equals(LOGIN_PAGE) || currentPage.equals("")) {

			RootPanel.get("menu").removeStyleName("menu");
			RootPanel.get("page").removeStyleName("page");
			RootPanel.get("login").add(this.session.getPage(LOGIN_PAGE));

		} else if (currentPage.subSequence(0, 5).equals(PROFESSOR_PAGES)) {

			RootPanel.get("menu").add(this.session.getPage(PROFESSOR_MENU));
			if (currentPage.equals(PROFESSOR_HOMEPAGE)) {

				RootPanel.get("page").add(
						this.session.getPage(PROFESSOR_HOMEPAGE));

			} else if (currentPage.equals(SECRETARY_CURSUS_EDITOR)) {

				RootPanel.get("page").add(
						this.session.getPage(SECRETARY_CURSUS_EDITOR));

			} else if (currentPage.equals(PROFESSOR_TEACHING)) {

				RootPanel.get("page").add(
						this.session.getPage(PROFESSOR_TEACHING));

			} else if(currentPage.contains(PROFESSOR_PLANNING_COURSE)) {

				RootPanel.get("page").add(this.session.getPage(PROFESSOR_PLANNING_COURSE));

			} else if(currentPage.contains(PROFESSOR_PLANNING_WORKS)) {

				RootPanel.get("page").add(this.session.getPage(PROFESSOR_PLANNING_WORKS));

			} else if(currentPage.contains(PROFESSOR_STUDENTS)) {

				RootPanel.get("page").add(
						this.session.getPage(PROFESSOR_STUDENTS));

			} else if (currentPage.contains(PROFESSOR_EDITOR)) {

				RootPanel.get("page").add(
						this.session.getPage(PROFESSOR_EDITOR));

			} 
		} else if (currentPage.subSequence(0, 5).equals(STUDENT_PAGES)) {

			// Gestion des pages des etudiants.

		} else if (currentPage.subSequence(0, 5).equals(SECRETARY_PAGES)) {

			RootPanel.get("menu").add(this.session.getPage(SECRETARY_MENU));

			if (currentPage.equals(SECRETARY_HOMEPAGE)) {

				RootPanel.get("page").add(
						this.session.getPage(SECRETARY_HOMEPAGE));

			} else if (currentPage.contains(SECRETARY_CURSUS_EDITOR)) {

				RootPanel.get("page").add(
						this.session.getPage(SECRETARY_CURSUS_EDITOR));
			}

		} else if (currentPage.subSequence(0, 5).equals(ADMIN_PAGES)) {

			// Gestion des pages admin.

		} else {
			RootPanel.get("menu").removeStyleName("menu");
			RootPanel.get("page").removeStyleName("page");
			RootPanel.get("login").add(this.session.getPage(LOGIN_PAGE));
		}
	}

	public static String getSHA1(String string) {
		byte[] output = null;
		try {
			MessageDigest md = MessageDigest.getInstance("SHA1");
			md.update(string.getBytes());
			output = md.digest();
		} catch (Exception e) {
			System.err.println("Exception: " + e);
		}

		return bytesToHex(output);
	}

	private static String bytesToHex(byte[] b) {
		if (b == null) {
			return "";
		}

		char hexDigit[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
				'A', 'B', 'C', 'D', 'E', 'F' };
		StringBuffer buf = new StringBuffer();
		for (int j = 0; j < b.length; j++) {
			buf.append(hexDigit[(b[j] >> 4) & 0x0f]);
			buf.append(hexDigit[b[j] & 0x0f]);
		}
		return buf.toString();
	}

	/**
	 * Redirect the browser to the given URL.
	 * 
	 * @param url
	 *            the URL to redirect.
	 */
	public static native void redirect(String url)/*-{
													$wnd.location = url;
													}-*/;
}
